package com.yuxl.admin.manager.auth.security.filter;

import com.yuxl.admin.common.security.config.JwtProperties;
import com.yuxl.admin.common.security.service.JwtService;
import com.yuxl.admin.common.security.service.RedisTokenService;
import com.yuxl.admin.manager.auth.core.entity.AuthRole;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.NonNull;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter implements WebFilter {

    private final JwtService jwtService;
    private final RedisTokenService redisTokenService;
    private final JwtProperties jwtProperties;

    @Override
    @NonNull
    public Mono<Void> filter(@NonNull ServerWebExchange exchange, @NonNull WebFilterChain chain) {
        String token = extractToken(exchange);
        log.debug("提取到的令牌: {}", token);

        if (token != null && jwtService.validateToken(token)) {
            String username = jwtService.extractUsername(token);
            log.debug("从令牌中提取的用户名: {}", username);

            return redisTokenService.tokenExists(username, token)
                    .flatMap(exists -> {
                        if (exists) {
                            log.debug("令牌在Redis中存在，用户: {}", username);
                            List<AuthRole> roles = jwtService.extractRoles(token);
                            List<SimpleGrantedAuthority> authorities = roles.stream()
                                    .map(k->new SimpleGrantedAuthority(k.getName()))
                                    .collect(Collectors.toList());

                            UsernamePasswordAuthenticationToken auth = 
                                new UsernamePasswordAuthenticationToken(username, token, authorities);

                            return chain.filter(exchange)
                                    .contextWrite(ReactiveSecurityContextHolder.withAuthentication(auth));
                        } else {
                            log.warn("令牌在Redis中不存在，用户: {}", username);
                            return chain.filter(exchange);
                        }
                    });
        }
        log.debug("没有有效的令牌，继续过滤器链");
        return chain.filter(exchange);
    }

    private String extractToken(ServerWebExchange exchange) {
        String bearerToken = exchange.getRequest().getHeaders().getFirst(jwtProperties.getHeaderKey());
        if (bearerToken != null && bearerToken.startsWith(jwtProperties.getBearerToken())) {
            return bearerToken.substring(7);
        }
        return null;
    }
}
